package com.wh.user.service.impl;

import cn.hutool.core.util.RadixUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wh.basic.utils.AliyunSmsUtils;
import com.wh.org.exception.BusinessException;
import com.wh.user.dao.IUserDao;
import com.wh.user.dto.SmsCodeDto;
import com.wh.user.pojo.User;
import com.wh.user.service.IUserService;
import com.wh.user.service.IVerifyCodeService;
import com.wh.user.utils.MathCodeTextCreator;
import com.wh.user.utils.VerifyCodeUtils;
import org.apache.xmlbeans.impl.regex.REUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    public static final String REG_MOBILE = "^(12[1-3]\\d{8})|[1][3-9]\\d{9}$|^([5|6|7|9])\\d{7}$|^[0][9]\\d{8}$|^[6]\\d{7}$";
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IUserDao userDao;


    /**
     * 用redis存储随机验证码，用工具类合并图片和验证码返回
     *
     * @param key
     * @return
     */
    @Override
    public String imageVerifyCode(String key) {

        //1.获取随机验证码-算术公式随机字符串
        String code = MathCodeTextCreator.getMathCode();
        //2.处理字符串(1+3?=@4)
        String[] strs = code.split("@");
        String mathCode = strs[0];
        String mathResult = strs[1];
        //3.将算术公式验证码的结果存放到redis，设置5分钟过期
        redisTemplate.opsForValue().set(key, mathResult, 5, TimeUnit.MINUTES);
        //4.把算术公式验证码的公式合并到图片，使用Base64编码。并返回base64编码的字符串
        return VerifyCodeUtils.verifyCode(115, 40, mathCode);
    }

    @Transactional
    @Override
    public void phoneVerifyCode(SmsCodeDto smsCodeDto) {
        String phone = smsCodeDto.getPhone();
        String imageCode = smsCodeDto.getImageCode();
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        //1.校验 - 空值校验
            if (StrUtil.isEmpty(phone)||StrUtil.isEmpty(imageCode)){
                throw new BusinessException("手机号或，，不能为空");
            }
        //2.校验 - 图片验证码校验  //2.1.图片验证码是否过期 //2.2.图片验证码是否正确
        Object key = redisTemplate.opsForValue().get(imageCodeKey);
            if (key == null){
                throw new BusinessException("图形验证码已经过期");
            }
            if (!imageCode.equalsIgnoreCase(key.toString())){
                System.err.println(imageCode);
                System.err.println(key.toString());
                throw new BusinessException("图形验证码错误");
            }
        //3.校验 - 手机号是否被注册 - 查询t_user表
        QueryWrapper<User> qw = new QueryWrapper<>();
            qw.eq("phone",smsCodeDto.getPhone());
            User user = userDao.selectOne(qw);
            if (user != null){
                throw new BusinessException("手机号已经被注册，请登录");
            }
        //4.判断原来的验证码是否有效【3分钟过期 - redis】，从redis是否能拿到通过

        //从redis中拿验证码
            Object phoneCode = redisTemplate.opsForValue().get("register:" + phone);
            String code = null;      //用于保存验证码
            if (phoneCode==null){   //没有注册过或者手机号验证码已经过期
                code=RandomUtil.randomNumbers(4);  //生成四味验证码，用于最后发送
            }else {       //不等于空 验证码没有过期 ，判断发送时间，时间不到一分钟责提示 超过责重新发同样码
                 //之前的验证码设置的时间戳
                long aLong = Long.parseLong(phoneCode.toString().split(":")[1]);
                if (System.currentTimeMillis()-aLong<(60*1000)){
                    throw new BusinessException("提交过于频繁，请稍后");
                }else {
                    //如果过了重发时间 - 可以再次发送验证码
                    code = phoneCode.toString().split(":")[0];
                }
            }
        // 5  讲key和验证码保存在redis，重新设置过期时间3分钟
        redisTemplate.opsForValue().set("register:"+phone,code+":"+System.currentTimeMillis(),5,TimeUnit.MINUTES);
        //6发送
        AliyunSmsUtils.sendSmsCaptcha(phone,code);
    }

    @Override
    public void binderVerifyCode(SmsCodeDto smsCodeDto) {
        String phone = smsCodeDto.getPhone();

        //一：校验：空值校验 - 前端和后端都可以校验手机格式问题
        boolean correctMobile = ReUtil.isMatch(REG_MOBILE, phone);
        if (StrUtil.isEmpty(phone)||correctMobile==false){
            throw new BusinessException("信息不能为空或者手机号格式不正确");
        }
        //二：校验：手机号码是否注册过（两个手机号不能绑定一个微信）
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("phone",phone);
        User user = userDao.selectOne(qw);
        if (user!=null){ //根据手机号查到了 = 手机已经注册了
            throw new BusinessException("该号码已经注册了");
        }
        //四：直接从redis获取手机验证码：key【业务🗡:手机号】
        Object o = redisTemplate.opsForValue().get("binder:" + phone);
        //1.没有获取到 = 第一次发送或者过期了，调用RandomUtil工具类重新生成
        String code = null;
        if (o==null){
            code = RandomUtil.randomNumbers(32);
        }else {
            //2.获取到了 = 没有过期，判断重发时间【时间戳】
            long oldTime = Long.parseLong(o.toString().split(":")[1]);//之前的验证码设置的时间戳
            if (System.currentTimeMillis()-oldTime<(60*1000)){
                throw new BusinessException("操作过于频繁，稍后");
            }else {
                //b.如果过了重发时间 - 可以获取新的验证码【用没有过期的 - code:时间戳】
                code = o.toString().split(":")[0];
            }
        }

        //五：讲key和验证码保存在redis，重新设置过期时间3分钟【如果是用以前的-这句话就刷新了过期时间】
        redisTemplate.opsForValue().set("binder:" + phone,code+":"+System.currentTimeMillis(),3,TimeUnit.MINUTES);
        //六：调用短信的工具类发送短信
        //SmsUtils.sendSms(phone,"你的手机验证码是：" + code +",请在3分钟内使用!!!");
        System.out.println("你的手机验证码是：" + code +",请在3分钟内使用!!!");
    }

}